<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="DMghH" id="DMghH"><span data-lake-id="u4824d178" id="u4824d178">典型回答</span></h1>
  <p data-lake-id="u5a646446" id="u5a646446"><span data-lake-id="u05413c11" id="u05413c11">​</span><br></p>
  <p data-lake-id="u7280925a" id="u7280925a"><span data-lake-id="u10c739d0" id="u10c739d0">Redis是一种KV的存储结构，他的key是字符串类型，值也支持字符串，所以字符串是redis中最常见的一个类型了。</span><strong><span data-lake-id="u6a67215b" id="u6a67215b">Redis自己本身是通过C语言实现的</span></strong><span data-lake-id="u7cdf67d6" id="u7cdf67d6">，但是他并没有直接使用C语言中的字符数组的方式来实现字符串，而是自己实现了一个SDS（Simple Dynamic Strings），即简单动态字符串，这是为什么呢？</span></p>
  <p data-lake-id="u57cef3cf" id="u57cef3cf"><span data-lake-id="u462be601" id="u462be601">​</span><br></p>
  <p data-lake-id="ucc2edf35" id="ucc2edf35"><span data-lake-id="u8a399d6b" id="u8a399d6b">首先，因为</span><strong><span data-lake-id="uf91436d5" id="uf91436d5">字符串在Redis中使用实在是太广泛了</span></strong><span data-lake-id="u0f3ce6c9" id="u0f3ce6c9"> ，所以对他的基本要求就有两点，</span><strong><span data-lake-id="u873fbd84" id="u873fbd84">第一就是要支持任意字符的存储，第二就是各种操作需要高效。</span></strong></p>
  <p data-lake-id="u20199746" id="u20199746"><span data-lake-id="u51119e1d" id="u51119e1d">​</span><br></p>
  <p data-lake-id="u07578c9e" id="u07578c9e"><span data-lake-id="ub9512223" id="ub9512223">接着我们看看C语言中字符串的实现方式有什么问题呢？很多人可能都忘了，我帮大家回忆一下，C语言中，字符串是通过字符数组实现的，底层呢是开辟了一块连续的空间，依次存放字符串中的每一个字符。为了表示字符串的结束，他会在字符数组的最后一个字符处记录</span><code data-lake-id="u2739f2a2" id="u2739f2a2"><span data-lake-id="ud39db844" id="ud39db844">\0</span></code><span data-lake-id="u20fa1b8d" id="u20fa1b8d">，</span></p>
  <p data-lake-id="ucbe4c217" id="ucbe4c217"><span data-lake-id="u59dd65b0" id="u59dd65b0">​</span><br></p>
  <p data-lake-id="u82e30046" id="u82e30046"><span data-lake-id="u2cf67c92" id="u2cf67c92">也就是说，在C语言中，当识别到字符数组中的</span><code data-lake-id="uf9260b05" id="uf9260b05"><span data-lake-id="uc102aead" id="uc102aead">\0</span></code><span data-lake-id="u9aa09904" id="u9aa09904">字符的时候，就认为字符串结束了，那么这么做会带来哪些问题呢？</span></p>
  <p data-lake-id="u722b3df8" id="u722b3df8"><span data-lake-id="u1bfb392c" id="u1bfb392c">​</span><br></p>
  <p data-lake-id="u22771d1f" id="u22771d1f"><span data-lake-id="u169d0d67" id="u169d0d67">就是</span><strong><span data-lake-id="ucd2cf72e" id="ucd2cf72e">这样实现的字符串中就不能保存任意内容了，至少</span></strong><code data-lake-id="u495b47f9" id="u495b47f9"><strong><span data-lake-id="uf9b6d88c" id="uf9b6d88c">\0</span></strong></code><strong><span data-lake-id="ua47516f2" id="ua47516f2">就不行</span></strong><span data-lake-id="uc8ebcd63" id="uc8ebcd63">，因为遇到他的时候就直接截断了，这肯定是接受不了的。</span></p>
  <p data-lake-id="u25d00266" id="u25d00266"><span data-lake-id="ue66af7b7" id="ue66af7b7">​</span><br></p>
  <p data-lake-id="u84898671" id="u84898671"><span data-lake-id="u2abfbe33" id="u2abfbe33">还有就是因为</span><strong><span data-lake-id="u9dde4f65" id="u9dde4f65">C中的字符串以</span></strong><code data-lake-id="u83ae72eb" id="u83ae72eb"><strong><span data-lake-id="uaabd5766" id="uaabd5766">\0</span></strong></code><strong><span data-lake-id="u7d40a69e" id="u7d40a69e">作为识别字符串结束的方式，所以他的字符串长度判断、字符串追加等操作，都需要从头开始遍历，一直遍历到</span></strong><code data-lake-id="uea17d514" id="uea17d514"><strong><span data-lake-id="u0223051f" id="u0223051f">\0</span></strong></code><strong><span data-lake-id="u38098384" id="u38098384">的时候再返回长度或者做追加。这就使得字符串相关的操作效率都很低。</span></strong></p>
  <p data-lake-id="ub66c8439" id="ub66c8439"><span data-lake-id="u30741f71" id="u30741f71">​</span><br></p>
  <p data-lake-id="u5581a52c" id="u5581a52c"><span data-lake-id="u4567d428" id="u4567d428">那么，想要解决上面的两个问题要怎么办呢？那就是</span><strong><span data-lake-id="u68ca587b" id="u68ca587b">在用字符数组表示字符串的同时，在这个字符串中增加一个表示分配给该字符数组的总长度的</span></strong><code data-lake-id="u27931fc1" id="u27931fc1"><strong><span data-lake-id="u081f8297" id="u081f8297">alloc</span></strong></code><strong><span data-lake-id="u3b0ba0f7" id="u3b0ba0f7">字段，和一个表示字符串现有长度的</span></strong><code data-lake-id="u19ba4865" id="u19ba4865"><strong><span data-lake-id="u9f385c2d" id="u9f385c2d">len</span></strong></code><strong><span data-lake-id="u9c97c671" id="u9c97c671">字段。这样在获取长度的时候就不依赖</span></strong><code data-lake-id="u2d6da66c" id="u2d6da66c"><strong><span data-lake-id="u42320256" id="u42320256">\0</span></strong></code><strong><span data-lake-id="u15458997" id="u15458997">了，直接返回</span></strong><code data-lake-id="ude8f6937" id="ude8f6937"><strong><span data-lake-id="uf72d265e" id="uf72d265e">len</span></strong></code><strong><span data-lake-id="uacd41e47" id="uacd41e47">的值就行了。</span></strong></p>
  <p data-lake-id="u2fecbb1e" id="u2fecbb1e"><span data-lake-id="udfe1f5df" id="udfe1f5df">​</span><br></p>
  <p data-lake-id="u85dd1cf3" id="u85dd1cf3"><span data-lake-id="uc9f96297" id="uc9f96297">还有呢，就是在做追加操作的时候，只需要判断新追加的部分的</span><code data-lake-id="u015cd156" id="u015cd156"><span data-lake-id="ucdb5108c" id="ucdb5108c">len</span></code><span data-lake-id="ubb20898b" id="ubb20898b">加上已有的</span><code data-lake-id="u7a9e21f6" id="u7a9e21f6"><span data-lake-id="ufd079347" id="ufd079347">len</span></code><span data-lake-id="u2ee8c66f" id="u2ee8c66f">是否大于</span><code data-lake-id="u430163e6" id="u430163e6"><span data-lake-id="uc7706683" id="uc7706683">alloc</span></code><span data-lake-id="u5c8c0d05" id="u5c8c0d05">，如果超过就重新再申请新空间，如果没超过，就直接进行追加就行了。</span></p>
  <p data-lake-id="ua6a88000" id="ua6a88000"><span data-lake-id="u3af7f9e7" id="u3af7f9e7">​</span><br></p>
  <p data-lake-id="ub1ad7997" id="ub1ad7997"><span data-lake-id="uac8406c0" id="uac8406c0">还有很多其他操作，比如复制、比较等都可以使用类似的思想高效的操作。</span></p>
 </body>
</html>